package com.shop.shopmall.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.shop.shopmall.dto.LoginDto;
import com.shop.shopmall.pojo.Menu;
import com.shop.shopmall.pojo.User;
import com.shop.shopmall.pojo.UserRole;
import com.shop.shopmall.service.UserRoleService;
import com.shop.shopmall.service.UserService;
import com.shop.shopmall.utils.JwtUtil;
import com.shop.shopmall.utils.ValidCodeUtil;
import com.shop.shopmall.vo.Result;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 用户管理模块控制器
 * @author jamie
 */
@RestController
@RequestMapping("/admin")
public class UserController {

    @Autowired
    UserService userService;

    @Autowired
    UserRoleService userRoleService;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    @Lazy // 启用懒加载，解决security和service循环依赖问题
    private PasswordEncoder passwordEncoder;

    /**
     * 用户登录接口
     *
     * @param loginDto 登录信息数据传输对象，包含用户名和密码
     * @return 登录结果，包含成功或失败的信息
     */
    @PostMapping("/login")
    public Result<?> login(@RequestBody LoginDto loginDto) {
        return userService.login(loginDto);
    }


    /**
     * 获取当前登录用户的菜单列表。
     *
     * @param request HTTP请求对象，用于获取请求头中的认证信息
     * @return 返回包含用户菜单的结果对象
     */
    @GetMapping("/getMenu")
    public Result<?> getMenu(HttpServletRequest request) {
        // 从请求头中获取Token
        String token = request.getHeader("authorization").replaceAll("Bearer", "").trim();
        // 从Token中解析出用户名
        String userName = JwtUtil.getUserName(token);
        // 查询用户信息
        LambdaQueryWrapper<User> userQuery = new LambdaQueryWrapper<>();
        userQuery.eq(User::getUsername, userName);
        User user = userService.getOne(userQuery);
        // 获取用户对应的菜单列表
        List<Menu> menus = userService.getMenuByUserId(user.getId());
        return Result.success(menus);
    }

    /**
     * 生成验证码图片，并将验证码存储到Redis中，设置有效期为5分钟
     *
     * @param response HTTP响应对象，用于输出验证码图片
     * @throws IOException 如果在生成或输出图片时发生错误
     */
    @GetMapping("/validCode")
    public void getValidPicture(HttpServletResponse response) throws IOException {
        // 创建验证码生成工具，设置图片宽度、高度、字体、背景色和字符集
        ValidCodeUtil validCodeUtil = new ValidCodeUtil(100, 40, new String[]{"宋体", "楷体", "隶书", "黑体"}, Color.WHITE, "1234567890");
        // 生成验证码图片
        BufferedImage image = validCodeUtil.getImage();
        // 获取生成的验证码字符串
        String validCode = validCodeUtil.getValidCode();
        System.out.println("validCode: " + validCode);
        // 将验证码存入Redis，键为"validCode"，有效期60秒
        redisTemplate.opsForValue().set("validCode", validCode, 60*5, TimeUnit.SECONDS);
        // 输出验证码图片到响应输出流
        ValidCodeUtil.output(image, response.getOutputStream());
    }

    /**
     * 分页获取用户信息列表。
     *
     * @param user 包含查询条件的用户对象
     * @param pageSize 每页显示的记录数
     * @param pageNum 当前页码
     * @return 返回包含用户信息分页结果的结果对象
     */
    @PostMapping("/{pageSize}/{pageNum}")
    public Result<?> getUsers(@RequestBody User user,
                              @PathVariable Integer pageSize,
                              @PathVariable Integer pageNum) {
        IPage<User> userPage = userService.getUsers(user, pageSize, pageNum);
        return Result.success(userPage);
    }

    /**
     * 新增用户信息，并为用户分配角色。
     *
     * @param user 包含用户信息和角色ID列表的用户对象
     * @return 返回操作结果
     */
    @Transactional
    @PostMapping("/add")
    public Result<?> addUser(@RequestBody User user) {
        // 设置用户状态为"1"（启用）
        user.setStatus("1");
        // 对用户密码进行加密处理
        String encodedPassword = passwordEncoder.encode(user.getPassword());
        user.setPassword(encodedPassword);
        // 保存用户信息
        userService.save(user);
        // 为用户分配角色
        List<UserRole> userRoles = new ArrayList<>();
        for (Integer roleId : user.getRoles()) {
            UserRole userRole = new UserRole();
            userRole.setRid(roleId);
            userRole.setUid(user.getId());
            userRoles.add(userRole);
        }
        userRoleService.saveBatch(userRoles);
        return Result.success();
    }

    /**
     * 修改用户信息，并更新用户的角色关联。
     *
     * @param user 包含更新后的用户信息和角色ID列表的用户对象
     * @return 返回操作结果
     */
    @Transactional
    @PutMapping
    public Result<?> updateUser(@RequestBody User user) {
        // 更新用户信息
        userService.updateById(user);
        // 删除用户原有的角色关联
        LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserRole::getUid, user.getId());
        userRoleService.remove(queryWrapper);
        // 为用户重新分配角色
        List<UserRole> userRoles = new ArrayList<>();
        for (Integer roleId : user.getRoles()) {
            UserRole userRole = new UserRole();
            userRole.setRid(roleId);
            userRole.setUid(user.getId());
            userRoles.add(userRole);
        }
        userRoleService.saveBatch(userRoles);
        return Result.success();
    }

    /**
     * 删除用户信息及其角色关联。
     *
     * @param id 要删除的用户ID
     * @return 返回操作结果
     */
    @Transactional
    @DeleteMapping("/{id}")
    public Result<?> deleteUser(@PathVariable int id) {
        // 删除用户信息
        userService.removeById(id);
        // 删除用户与角色的关联信息
        LambdaQueryWrapper<UserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserRole::getUid, id);
        userRoleService.remove(queryWrapper);
        return Result.success();
    }

    /**
     * 切换用户状态
     * @param id 用户的唯一标识符
     * @param status 要设置的新状态值
     * @return 操作结果的封装对象
     */
    @GetMapping("/switchStatus/{id}/{status}")
    public Result<?> switchStatus(@PathVariable int id, @PathVariable int status) {
        userService.updateStatus(id, status);
        return Result.success();
    }

    /**
     * 重置用户密码
     * @param id 用户ID
     * @param user 包含新密码的用户对象
     * @return 操作结果
     */
    @PutMapping("/resetPass/{id}")
    public Result<?> resetPassword(@PathVariable int id, @RequestBody User user) {
        // 使用BCryptPasswordEncoder对新密码进行加密
        String password = new BCryptPasswordEncoder().encode(user.getPassword());
        // 调用服务层方法，更新用户密码
        userService.updatePass(id, password);
        return Result.success();
    }

}
